{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# ufunc 对象"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Numpy** 有两种基本对象：`ndarray (N-dimensional array object)` 和 `ufunc (universal function object)`。`ndarray` 是存储单一数据类型的多维数组，而 `ufunc` 则是能够对数组进行处理的函数。\n",
    "\n",
    "例如，我们之前所接触到的二元操作符对应的 **Numpy** 函数，如 `add`，就是一种 `ufunc` 对象，它可以作用于数组的每个元素。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([2, 4, 6])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([0,1,2])\n",
    "b = np.array([2,3,4])\n",
    "\n",
    "np.add(a, b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "查看支持的方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['__call__',\n",
       " '__class__',\n",
       " '__delattr__',\n",
       " '__doc__',\n",
       " '__format__',\n",
       " '__getattribute__',\n",
       " '__hash__',\n",
       " '__init__',\n",
       " '__name__',\n",
       " '__new__',\n",
       " '__reduce__',\n",
       " '__reduce_ex__',\n",
       " '__repr__',\n",
       " '__setattr__',\n",
       " '__sizeof__',\n",
       " '__str__',\n",
       " '__subclasshook__',\n",
       " 'accumulate',\n",
       " 'at',\n",
       " 'identity',\n",
       " 'nargs',\n",
       " 'nin',\n",
       " 'nout',\n",
       " 'ntypes',\n",
       " 'outer',\n",
       " 'reduce',\n",
       " 'reduceat',\n",
       " 'signature',\n",
       " 'types']"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dir(np.add)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "除此之外，大部分能够作用于数组的数学函数如三角函数等，都是 `ufunc` 对象。\n",
    "\n",
    "特别地，对于二元操作符所对应的 `ufunc` 对象，支持以下方法："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## reduce 方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "    op.reduce(a)\n",
    "\n",
    "将`op`沿着某个轴应用，使得数组 `a` 的维数降低一维。\n",
    "\n",
    "add 作用到一维数组上相当于求和：\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "y & = add.recuce(a) \\\\\n",
    "& = a[0] + a[1] + ... + a[N-1] \\\\\n",
    "& = \\sum_{n=0}^{N-1} a[n]\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "10"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([1,2,3,4])\n",
    "\n",
    "np.add.reduce(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "多维数组默认只按照第一维进行运算："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([5, 7, 9])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([[1,2,3],[4,5,6]])\n",
    "\n",
    "np.add.reduce(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "指定维度："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 6, 15])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.add.reduce(a, 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "作用于字符串："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'abcdef'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array(['ab', 'cd', 'ef'], np.object)\n",
    "\n",
    "np.add.reduce(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "逻辑运算："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([1,1,0,1])\n",
    "\n",
    "np.logical_and.reduce(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.logical_or.reduce(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## accumulate 方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "    op.accumulate(a)\n",
    "\n",
    "`accumulate` 可以看成保存 `reduce` 每一步的结果所形成的数组。\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "y & = add.accumulate(a) \\\\\n",
    "& = \\left[\\sum_{n=0}^{0} a[n], \\sum_{n=0}^{1} a[n], ..., \\sum_{n=0}^{N-1} a[n]\\right]\n",
    "\\end{align}\n",
    "$$\n",
    "\n",
    "与之前类似："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 1,  3,  6, 10])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([1,2,3,4])\n",
    "\n",
    "np.add.accumulate(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array(['ab', 'abcd', 'abcdef'], dtype=object)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array(['ab', 'cd', 'ef'], np.object)\n",
    "\n",
    "np.add.accumulate(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ True,  True, False, False], dtype=bool)"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([1,1,0,1])\n",
    "\n",
    "np.logical_and.accumulate(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ True,  True,  True,  True], dtype=bool)"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.logical_or.accumulate(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## reduceat 方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "    op.reduceat(a, indices)\n",
    "\n",
    "`reduceat` 方法将操作符运用到指定的下标上，返回一个与 `indices` 大小相同的数组：\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "y & = add.reduceat(a, indices) \\\\\n",
    "& = \\left[\\sum_{n=indice[0]}^{indice[1]-1} a[n], \\sum_{n=indice[1]}^{indice[2]-1} a[n], ..., \\sum_{n=indice[-1]}^{N-1} a[n]\\right]\n",
    "\\end{align}\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([60, 90])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([0, 10, 20, 30, 40, 50])\n",
    "indices = np.array([1,4])\n",
    "\n",
    "np.add.reduceat(a, indices)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里，`indices` 为 `[1, 4]`，所以 `60` 表示从下标1（包括）加到下标4（不包括）的结果，`90` 表示从下标4（包括）加到结尾的结果。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## outer 方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "    op.outer(a, b)\n",
    "\n",
    "对于 `a` 中每个元素，将 `op` 运用到它和 `b` 的每一个元素上所得到的结果："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 3],\n",
       "       [2, 3, 4]])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([0,1])\n",
    "b = np.array([1,2,3])\n",
    "\n",
    "np.add.outer(a, b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注意有顺序的区别："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2],\n",
       "       [2, 3],\n",
       "       [3, 4]])"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.add.outer(b, a)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
